#if !defined(ximera_common_signal_hpp)
#define ximera_common_signal_hpp

// -----------------------------------------------------------

#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>

namespace ximera
{
    //! \brief A signal connection
    //!
    //! This is a slot connection on a signal. You can call its
    //! disconnect member function to disconnect the slot.
    //! \code
    //! SignalConnection conn = signal.connect(&some_function);
    //! conn.disconnect();
    //! \endcode
    //! \sa Signal
    typedef boost::signals::connection SignalConnection;

    //! \brief A scoped signal connection
    //!
    //! This is a slot connection on a signal. It will automatically
    //! disconnect the slot when it goes out of scope.
    //! \code
    //! {
    //!     ScopedSignalConnection conn = signal.connect(&some_function);
    //!     // connected
    //! }
    //! // disconnected
    //! \endcode
    //! \sa Signal
    //! \sa SignalConnection
    typedef boost::signals::scoped_connection ScopedSignalConnection;
    
    //! \brief A slots and signals class
    //!
    //! This class easily allows flexible and powerful callbacks. An
    //! example usage is:
    //! \code
    //! class X
    //! {
    //!     void f(int) {}
    //! };
    //! 
    //! void g(int) {}
    //! 
    //! int main()
    //! {
    //!     Signal<void (int)> events;
    //!     events += &g;
    //! 
    //!     X x1;
    //!     events += boost::bind(&X::f, &x1);
    //! 
    //!     events(10);  // calls x1.f() and g()
    //! }
    //! \endcode
    template <typename Signature>
    class Signal : public boost::signal<Signature>
    {
    public:
        //! Connects a slot to this signal
        SignalConnection operator+=(typename boost::signal<Signature>::slot_type const& slot)
        {
            return connect(slot);
        }

        //! Disconnects a slot from this signal
        template <typename Slot>
        void operator-=(Slot const& slot)
        {
            return disconnect(slot);
        }
    };

    template <typename Signature>
    class SignalAccess
    {
    public:
        SignalAccess(Signal<Signature>& sig)
            : sig(sig) {}

        SignalConnection operator+=(typename boost::signal<Signature>::slot_type const& slot)
        {
            return sig.connect(slot);
        }

        template <typename Slot>
        void operator-=(Slot const& slot)
        {
            return sig.disconnect(slot);
        }

    private:
        Signal<Signature>& sig;
    };
}

// -----------------------------------------------------------

#endif